Redux Toolkit Thunk - createAsyncThunk
Redux Toolkit(RTK)은 Redux의 비동기 흐름을 표중화한 도구이며,
createAsyncThunk는 그중 비동기 로직을 가장 안정적으로 관리하는 공식 방식입니다.
1️⃣ createAsynThunk가 필요한 이유
🔹 기존 Redux + Thunk의 문제점
- 액션 타입 3개(FETCH_START, FETCH_SUCCESS, FETCH_ERROR) 직접 관리
- 액션 크리에이터 따로, 리유서 따로, 비동기 로직 따로
- 로딩/성공/에러 상태 관리 코드 반복
- 타입스크립트 적용 시 추가 보일러플레이트 증가
👉 RTK의 createAsyncThunk는 이 모든 과정을 자동화합니다.
2️⃣ createAsyncThunk 기본 개념
createAsyncThunk는 비동기 요청을 하나의 thunk로 추상화하고 아래 3가지 "라이프사이클 액션"을 자동 생성합니다.
- pending (요청 시작)
- fulfilled (요청 성공)
- rejected (요청 실패)
🧐 예시
export const fetchUser = createAsyncThunk(
"user/fetchUser",
async (userId) => {
const res = await fetch(`/api/users/${userId}`);
return await res.json();
}
);
자동 생성되는 액션
- user/fetchUser/pending
- user/fetchUser/fulfilled
- user/fetchUser/rejected
3️⃣ Slice에서 비동기 상태 처리
Redux Toolkit에서는 extraReducers로 비동기 상태를 처리합니다.
const userSlice = createSlice({
name: "user",
initialState: {
data: null,
loading: false,
error: null,
},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.loading = false;
state.error = action.error;
});
},
});
-
pending상태- 비동기 요청 시작될 때 자동 호출
loading을true로 변경, 기존 오류 상태 초기화
-
fulfilled상태- 요청이 성공했을 때 실행
- 서버에서 받아온 데이터를 저장
-
rejected상태- 요청이 실패했을 때 실행
- 네트워크 에러, 서버 에러 등 다양한 오휴 정보를
action.error에서 받을 수 있음
4️⃣ Payload와 Error 커스터마이징
실무에서는 서버 에러 코드를 함께 전달해야 합니다. (rejectWithValue 활용)
export const login = createAsyncThunk(
"auth/login",
async (form, { rejectWithValue }) => {
try {
const res = await fetch("/api/login", {
method: "POST",
body: JSON.stringify(form),
});
if (!res.ok) {
const error = await res.json();
return rejectWithValue(error.message);
}
return res.json();
} catch (err) {
return rejectWithValue("네트워크 오류");
}
}
);
Slice
.addCase(login.rejected, (state, action) => {
state.error = action.payload;
})